use proc_macro::TokenStream;
use quote::{format_ident, quote};
use darling::FromDeriveInput;
use syn::{parse_macro_input, DeriveInput};

use super::DmaInfo;

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(uart))]
pub struct Config {
    init: String,
    uart: u8,
    baud_rate: u32,
}


pub fn build(input: TokenStream) -> TokenStream {

    let input = parse_macro_input!(input as DeriveInput);
    let config = Config::from_derive_input(&input).unwrap();
    let name = format_ident!("{}", config.init);

    let uart_name = match config.uart {
        1 | 2 | 3 => format!("usart{}", config.uart),
        4 => format!("uart{}", config.uart),
        _ => panic!("invalid uart"),
    };
    let tx_info = DmaInfo::with_name(&format!("{}_tx", uart_name));
    let rx_info = DmaInfo::with_name(&format!("{}_rx", uart_name));
    
    let tx_dma_name = tx_info.name;
    let rx_dma_name = rx_info.name;

    let tx_dma = tx_info.dma;
    let rx_dma = rx_info.dma;

    let tx_ch = tx_info.ch;
    let rx_ch = rx_info.ch;

    let baud_rate = config.baud_rate;
    let uart = config.uart;

    let expand = quote! {

        #[derive(DmaConfig, UartInit)]
        #[dma(
            init = "dma_init",
            ch(name = #tx_dma_name, dma = #tx_dma, ch = #tx_ch, size = 8, dir = "write", tcie),
            ch(name = #rx_dma_name, dma = #rx_dma, ch = #rx_ch, size = 8, dir = "read", circ)
        )]
        #[uart_config(uart = #uart, size = 8, baud_rate = #baud_rate)]
        struct #name;
    };
    expand.into()
}
